/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.groupbuy.api.controller;

import cn.hutool.core.util.StrUtil;
import com.yami.shop.bean.app.dto.OrderNumbersDto;
import com.yami.shop.bean.app.dto.ShopCartItemDto;
import com.yami.shop.bean.app.dto.UserAddrDto;
import com.yami.shop.bean.enums.ProdStatusEnums;
import com.yami.shop.bean.event.CalculateTransfeeEvent;
import com.yami.shop.bean.model.Sku;
import com.yami.shop.bean.model.UserAddr;
import com.yami.shop.common.constants.OrderCacheNames;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.i18n.LanguageEnum;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.CacheManagerUtil;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.groupbuy.comment.api.dto.ApiGroupActivityDto;
import com.yami.shop.groupbuy.comment.api.dto.ApiGroupSkuInfoDto;
import com.yami.shop.groupbuy.comment.api.dto.ApiGroupUserOrderDto;
import com.yami.shop.groupbuy.comment.api.param.ApiGroupOrderParam;
import com.yami.shop.groupbuy.comment.api.param.ApiGroupOrderSubmitParam;
import com.yami.shop.groupbuy.comment.enums.ActivityStatusEnum;
import com.yami.shop.groupbuy.comment.enums.GroupOrderStatusEnum;
import com.yami.shop.groupbuy.comment.enums.TeamStatusEnum;
import com.yami.shop.groupbuy.comment.model.GroupOrder;
import com.yami.shop.groupbuy.comment.model.GroupProd;
import com.yami.shop.groupbuy.comment.model.GroupTeam;
import com.yami.shop.groupbuy.comment.service.*;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.service.ProductService;
import com.yami.shop.service.SkuService;
import com.yami.shop.service.UserAddrService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import ma.glasnost.orika.MapperFacade;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author Yami
 */
@RestController
@RequestMapping("/p/group/order")
@Api(tags = "拼团订单接口")
@AllArgsConstructor
public class GroupOrderController {

    private final GroupTeamService groupTeamService;
    private final GroupOrderService groupOrderService;
    private final StringRedisTemplate stringRedisTemplate;
    private final CacheManagerUtil cacheManagerUtil;
    private final UserAddrService userAddrService;
    private final ApplicationContext applicationContext;
    private final MapperFacade mapperFacade;
    private final GroupProdService groupProdService;
    private final GroupSkuService groupSkuService;
    private final GroupActivityService groupActivityService;
    private final SkuService skuService;
    private final ProductService productService;


    @PostMapping("/confirm")
    @ApiOperation(value = "确认订单", notes = "传入参团/开团所需要的参数进行下单,如果用户为开团时拼团团队Id(groupTeamId)为0,如用户为开团则需要将拼团团队Id(groupTeamId)需要带上")
    public ResponseEntity<ApiGroupUserOrderDto> confirm(@Valid @RequestBody ApiGroupOrderParam apiGroupOrderParam) {
        String userId = SecurityUtils.getUser().getUserId();
        if (apiGroupOrderParam.getGroupTeamId() != 0) {
            GroupTeam groupTeam = groupTeamService.getById(apiGroupOrderParam.getGroupTeamId());
            if (Objects.isNull(groupTeam)) {
                // 未找到拼团团队信息
                throw new YamiShopBindException("yami.group.team.no.exist");
            }
            if (!TeamStatusEnum.IN_GROUP.value().equals(groupTeam.getStatus())) {
                // 拼团团队不在拼团中，不能参与拼团
                throw new YamiShopBindException("yami.group.team.no.join");
            }
            if (groupTeam.getEndTime() != null && System.currentTimeMillis() > groupTeam.getEndTime().getTime()) {
                //该拼团单不存在
                throw new YamiShopBindException("yami.group.order.no.exist");
            }
        }
        GroupProd groupProd = groupProdService.getGroupProdByGroupSkuId(apiGroupOrderParam.getGroupSkuId());
        if (Objects.isNull(groupProd) || !Objects.equals(groupProd.getStatus(), 1)) {
            // 活动商品不在正常状态
            throw new YamiShopBindException("yami.group.prod.status.error");
        }
        // 校验商品规格信息
        ApiGroupSkuInfoDto groupSkuInfoDto = groupSkuService.getSkuInfoByGroupSkuId(apiGroupOrderParam.getGroupSkuId());
        if (Objects.isNull(groupSkuInfoDto)) {
            // 活动商品规格已售空或已下架
            throw new YamiShopBindException("yami.group.prod.sold.out");
        }
        if (groupSkuInfoDto.getProdStatus() != ProdStatusEnums.NORMAL.getValue()) {
            // 活动商品不在正常状态
            throw new YamiShopBindException("yami.group.prod.status.error");
        }
        // 校验活动
        ApiGroupActivityDto groupActivityInfo = groupActivityService.getApiGroupActivityInfo(groupProd.getGroupActivityId(), groupProd.getProdId());
        if (!Objects.equals(groupActivityInfo.getActivityStatus(), ActivityStatusEnum.UNDER_WAY.value())) {
            // 拼团活动不在进行中，请稍后重试
            throw new YamiShopBindException("yami.group.no.progress");
        }
        if (groupSkuInfoDto.getStocks() != -1 && groupSkuInfoDto.getStocks() < apiGroupOrderParam.getProdCount()) {
            // 库存量不足，请重新选择购买数量
            throw new YamiShopBindException("yami.group.prod.insufficient.stock");
        }
        if (new Date().before(groupActivityInfo.getStartTime())){
            throw new YamiShopBindException("yami.group.order.less.start.time.error");
        }
        if (new Date().after(groupActivityInfo.getEndTime())){
            throw new YamiShopBindException("yami.group.order.more.end.time.error");
        }
        ApiGroupUserOrderDto apiGroupUserOrderDto = handleConfirmData(userId, groupProd, apiGroupOrderParam, groupSkuInfoDto, groupActivityInfo);
        return ResponseEntity.ok(apiGroupUserOrderDto);
    }

    @PostMapping("/submit")
    @ApiOperation(value = "提交订单，返回订单编号", notes = "根据订单信息，返回订单编号")
    public ResponseEntity<OrderNumbersDto> submitOrders(@Valid @RequestBody ApiGroupOrderSubmitParam apiGroupOrderSubmitParam) {
        String userId = SecurityUtils.getUser().getUserId();
        // 防止重复、同时提交
        boolean cad = RedisUtil.cad(OrderCacheNames.GROUP_ORDER_CONFIRM_UUID_KEY + OrderCacheNames.UNION  + userId, userId);
        if (!cad) {
            // 订单状态已经发生改变，请重新下单
            throw new YamiShopBindException("yami.order.status.check.change");
        }

        // 看看订单的标记有没有过期
        if (cacheManagerUtil.getCache(OrderCacheNames.GROUP_ORDER_CONFIRM_KEY,  userId) == null) {
            // 订单已过期，请重新下单
            throw new YamiShopBindException("yami.order.expired");
        }

        ApiGroupUserOrderDto hadConfirmOrder = cacheManagerUtil.getCache(OrderCacheNames.GROUP_ORDER_CONFIRM_KEY, userId);
        if (Objects.isNull(hadConfirmOrder)) {
            // 订单已过期，请重新下单
            throw new YamiShopBindException("yami.order.expired");
        }

        if (Objects.isNull(hadConfirmOrder.getUserAddrDto())) {
            // 请填写收货地址
            throw new YamiShopBindException("yami.delivery.address");
        }

        // 校验活动
        ApiGroupActivityDto apiGroupActivityInfo = groupActivityService.getApiGroupActivityInfo(hadConfirmOrder.getGroupActivityId(), hadConfirmOrder.getProdId());
        if (!Objects.equals(apiGroupActivityInfo.getActivityStatus(), ActivityStatusEnum.UNDER_WAY.value())) {
            // 拼团活动不在进行中，不能参与拼团
            throw new YamiShopBindException("yami.group.no.progress");
        }

        // 查看未完成的订单数量
        int unGroupOrderCount = groupOrderService.getUserUnGroupOrderCount(userId, hadConfirmOrder.getGroupProdId());
        if (unGroupOrderCount > 0) {
            throw new YamiShopBindException("yami.group.prod.has.group.order");
        }

        // 校验活动商品是否处于失效状态
        GroupProd groupProd = groupProdService.getGroupProdByGroupSkuId(hadConfirmOrder.getGroupSkuId());
        if (Objects.isNull(groupProd) || groupProd.getStatus() != 1) {
            // 活动商品已失效或不存在
            throw new YamiShopBindException("yami.activity.prod.no.exist");
        }
        List<GroupOrder> groupOrderList = groupOrderService.listByGroupProdId(groupProd.getGroupProdId(), userId);
        long count = groupOrderList.stream().filter(groupOrder -> Objects.equals(groupOrder.getStatus(), GroupOrderStatusEnum.WAITING_PAY.value())).count();
        if (count > 0) {
            // 您正在参加此活动，请在拼团成功后重试
            throw new YamiShopBindException("yami.group.user.join.group");
        }
        // 校验拼团团队是否可以参团
        if (Objects.nonNull(hadConfirmOrder.getGroupTempId()) && hadConfirmOrder.getGroupTempId() != 0) {
            GroupTeam groupTeam = groupTeamService.getById(hadConfirmOrder.getGroupTempId());
            if (!Objects.equals(TeamStatusEnum.IN_GROUP.value(), groupTeam.getStatus())) {
                // 拼团团队不在拼团中，不能参与拼团
                throw new YamiShopBindException("yami.group.team.no.join");
            }
            if(System.currentTimeMillis() > groupTeam.getEndTime().getTime()){
                // 该拼团团队已关闭，不能继续参团
                throw new YamiShopBindException("yami.group.order.no.exist");
            }
            long hadJoinCount = groupOrderList.stream().filter(item -> Objects.equals(item.getGroupTeamId(), groupTeam.getGroupTeamId())).count();
            if (hadJoinCount > 0) {
                // 您已参加过此团，不能重复参团
                throw new YamiShopBindException("yami.group.user.join.group.error");
            }
        }
        String orderNumber = groupOrderService.submit(userId, hadConfirmOrder, apiGroupOrderSubmitParam.getRemarks());
        // 移除缓存
        productService.removeProdCacheByProdId(hadConfirmOrder.getProdId(),LanguageEnum.LANGUAGE_ZH_CN.getLang());
        productService.removeProdCacheByProdId(hadConfirmOrder.getProdId(),LanguageEnum.LANGUAGE_EN.getLang());
        skuService.removeSkuCacheBySkuIdAndLang(hadConfirmOrder.getSkuId(),hadConfirmOrder.getProdId(), LanguageEnum.LANGUAGE_ZH_CN.getLang());
        skuService.removeSkuCacheBySkuIdAndLang(hadConfirmOrder.getSkuId(),hadConfirmOrder.getProdId(),LanguageEnum.LANGUAGE_EN.getLang());
        groupOrderService.removeConfirmOrderCache(userId);
        return ResponseEntity.ok(new OrderNumbersDto(orderNumber));
    }

    /**
     * 处理订单提交的数据
     * @param userId
     * @param groupProd
     * @param apiGroupOrderParam
     * @param groupSkuInfoDto
     * @param groupActivityInfo
     * @return
     */
    private ApiGroupUserOrderDto handleConfirmData(String userId, GroupProd groupProd, @Valid ApiGroupOrderParam apiGroupOrderParam, ApiGroupSkuInfoDto groupSkuInfoDto, ApiGroupActivityDto groupActivityInfo) {
        if (Objects.equals(groupActivityInfo.getHasMaxNum(), 1)) {
            Integer hasOrderCount = groupOrderService.getUserHadOrderCountByGroupProdId(userId, groupProd.getGroupProdId());
            if (hasOrderCount + apiGroupOrderParam.getProdCount() > groupActivityInfo.getMaxNum()) {
                String prodName = StrUtil.isEmpty(groupSkuInfoDto.getSkuName()) ? groupSkuInfoDto.getProdName() : groupSkuInfoDto.getSkuName();
                String message = I18nMessage.getMessage("yami.group.prod.shop.limit");
                String num = I18nMessage.getMessage("yami.seckill.num");
                String userNum = I18nMessage.getMessage("yami.group.user.shop.num");
                String nowNum = I18nMessage.getMessage("yami.group.user.now.shop");
                String maxNum = I18nMessage.getMessage("yami.group.prod.overstep.shop.limit");
                // 活动商品限购数量为x件，您已购买x件，现购x件，超出最大得购买数量
                throw new YamiShopBindException(message + groupActivityInfo.getMaxNum() + num+userNum
                        + hasOrderCount + num+nowNum+ apiGroupOrderParam.getProdCount() + num+maxNum);
            }
        }


        // 计算商品总金额
        double prodTotalPrice = Arith.mul(apiGroupOrderParam.getProdCount(), groupSkuInfoDto.getActPrice());

        // 计算运费
        ShopCartItemDto productItemDto = new ShopCartItemDto();
        productItemDto.setProdId(groupProd.getProdId());
        productItemDto.setSkuId(groupSkuInfoDto.getSkuId());
        productItemDto.setProdCount(apiGroupOrderParam.getProdCount());
        productItemDto.setProductTotalAmount(prodTotalPrice);
        productItemDto.setShopId(groupProd.getShopId());
        // 用户地址信息
        UserAddr userAddr = userAddrService.getUserAddrByUserId(apiGroupOrderParam.getAddrId(), userId);
        double transFee = 0.0;
        if (userAddr != null) {
            CalculateTransfeeEvent calculateTransfeeEvent = new CalculateTransfeeEvent(productItemDto, userAddr);
            applicationContext.publishEvent(calculateTransfeeEvent);
            transFee = calculateTransfeeEvent.getTransfee();
        }

        // 需要支付的总金额
        double orderTotalPrice = 0.0;
        // 是否享受团长价（团id为0表示这个团还没开始，也就是这个人是团长，因为id是long类型，所以用equals）
        if (Objects.equals(apiGroupOrderParam.getGroupTeamId(), 0L) && groupActivityInfo.getHasLeaderPrice() == 1) {
            orderTotalPrice = Arith.add(Arith.mul(apiGroupOrderParam.getProdCount(), groupSkuInfoDto.getLeaderPrice()), transFee);
        } else {
            // 参团为活动价格
            orderTotalPrice = Arith.add(prodTotalPrice, transFee);
        }

        Sku sku = skuService.getSkuBySkuId(groupSkuInfoDto.getSkuId(), I18nMessage.getDbLang());

        // 计算原来的商品总金额
        double oriTotalPrice = Arith.mul(apiGroupOrderParam.getProdCount(), sku.getPrice());
        // 用户此笔订单实付的商品金额
        double prodActualAmount = Arith.sub(orderTotalPrice, transFee);
        // 封装返回的信息
        ApiGroupUserOrderDto apiGroupUserOrderDto = mapperFacade.map(groupSkuInfoDto, ApiGroupUserOrderDto.class);
        apiGroupUserOrderDto.setUserAddrDto(mapperFacade.map(userAddr, UserAddrDto.class));
        apiGroupUserOrderDto.setGroupProdActualTotal(prodActualAmount);
        apiGroupUserOrderDto.setOrderTotalPrice(orderTotalPrice);
        // 原商品总价 - 用户此笔订单实付的商品金额(团购总不能没有优惠金额吧)
        apiGroupUserOrderDto.setDiscountPrice(Math.max(Arith.sub(oriTotalPrice, prodActualAmount), 0));
        apiGroupUserOrderDto.setTransfee(transFee);

        apiGroupUserOrderDto.setProdTotalPrice(oriTotalPrice);


        apiGroupUserOrderDto.setGroupActivityId(groupActivityInfo.getGroupActivityId());
        apiGroupUserOrderDto.setProdId(groupProd.getProdId());
        apiGroupUserOrderDto.setGroupTempId(apiGroupOrderParam.getGroupTeamId());
        apiGroupUserOrderDto.setGroupSkuId(apiGroupOrderParam.getGroupSkuId());
        apiGroupUserOrderDto.setProdTotalCount(apiGroupOrderParam.getProdCount());
        apiGroupUserOrderDto.setHasLeaderPrice(groupActivityInfo.getHasLeaderPrice());
        // 防止重复提交
        stringRedisTemplate.opsForValue().set(OrderCacheNames.GROUP_ORDER_CONFIRM_UUID_KEY + OrderCacheNames.UNION  + userId, userId);
        // 保存订单计算结果缓存，省得重新计算 并且 用户确认的订单金额与提交的一致
        cacheManagerUtil.putCache(OrderCacheNames.GROUP_ORDER_CONFIRM_KEY, userId,apiGroupUserOrderDto);
        return apiGroupUserOrderDto;
    }

}
